dea591
@@ -22,11 +22,10 @@
import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.WeakHashMap;
@@ -141,19 +140,20 @@
public class CachedIntrospectionResults {
 			results = (CachedIntrospectionResults) value;
 		}
 		if (results == null) {
-			// can throw BeansException
-			results = new CachedIntrospectionResults(beanClass);
 			// On JDK 1.5 and higher, it is almost always safe to cache the bean class...
 			// The sole exception is a custom BeanInfo class being provided in a non-safe ClassLoader.
-			if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
-					isClassLoaderAccepted(beanClass.getClassLoader()) ||
-					!ClassUtils.isPresent(beanClass.getName() + "BeanInfo", beanClass.getClassLoader())) {
+			boolean fullyCacheable =
+					ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
+					isClassLoaderAccepted(beanClass.getClassLoader());
+			if (fullyCacheable || !ClassUtils.isPresent(beanClass.getName() + "BeanInfo", beanClass.getClassLoader())) {
+				results = new CachedIntrospectionResults(beanClass, fullyCacheable);
 				classCache.put(beanClass, results);
 			}
 			else {
 				if (logger.isDebugEnabled()) {
 					logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
 				}
+				results = new CachedIntrospectionResults(beanClass, true);
 				classCache.put(beanClass, new WeakReference<CachedIntrospectionResults>(results));
 			}
 		}
@@ -216,7 +216,7 @@
public class CachedIntrospectionResults {
 	 * @param beanClass the bean class to analyze
 	 * @throws BeansException in case of introspection failure
 	 */
-	private CachedIntrospectionResults(Class beanClass) throws BeansException {
+	private CachedIntrospectionResults(Class beanClass, boolean cacheFullMetadata) throws BeansException {
 		try {
 			if (logger.isTraceEnabled()) {
 				logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
@@ -237,24 +237,29 @@
public class CachedIntrospectionResults {
 			if (logger.isTraceEnabled()) {
 				logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
 			}
-			this.propertyDescriptorCache = new HashMap<String, PropertyDescriptor>();
+			this.propertyDescriptorCache = new LinkedHashMap<String, PropertyDescriptor>();
 
 			// This call is slow so we do it once.
 			PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
 			for (PropertyDescriptor pd : pds) {
+				if (Class.class.equals(beanClass) && "classLoader".equals(pd.getName())) {
+					// Ignore Class.getClassLoader() method - nobody needs to bind to that
+					continue;
+				}
 				if (logger.isTraceEnabled()) {
 					logger.trace("Found bean property '" + pd.getName() + "'" +
 							(pd.getPropertyType() != null ? " of type [" + pd.getPropertyType().getName() + "]" : "") +
 							(pd.getPropertyEditorClass() != null ?
 									"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
 				}
-				pd = new GenericTypeAwarePropertyDescriptor(beanClass, pd.getName(), pd.getReadMethod(),
-						pd.getWriteMethod(), pd.getPropertyEditorClass());
+				if (cacheFullMetadata) {
+					pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
+				}
 				this.propertyDescriptorCache.put(pd.getName(), pd);
 			}
 		}
 		catch (IntrospectionException ex) {
-			throw new FatalBeanException("Cannot get BeanInfo for object of class [" + beanClass.getName() + "]", ex);
+			throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex);
 		}
 	}
 
@@ -275,12 +280,29 @@
public class CachedIntrospectionResults {
 				pd = this.propertyDescriptorCache.get(name.substring(0, 1).toUpperCase() + name.substring(1));
 			}
 		}
-		return pd;
+		return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
+				buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
 	}
 
 	PropertyDescriptor[] getPropertyDescriptors() {
-		Collection<PropertyDescriptor> descriptorCollection = this.propertyDescriptorCache.values();
-		return descriptorCollection.toArray(new PropertyDescriptor[descriptorCollection.size()]);
+		PropertyDescriptor[] pds = new PropertyDescriptor[this.propertyDescriptorCache.size()];
+		int i = 0;
+		for (PropertyDescriptor pd : this.propertyDescriptorCache.values()) {
+			pds[i] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
+					buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
+			i++;
+		}
+		return pds;
+	}
+
+	private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class beanClass, PropertyDescriptor pd) {
+		try {
+			return new GenericTypeAwarePropertyDescriptor(beanClass, pd.getName(), pd.getReadMethod(),
+					pd.getWriteMethod(), pd.getPropertyEditorClass());
+		}
+		catch (IntrospectionException ex) {
+			throw new FatalBeanException("Failed to re-introspect class [" + beanClass.getName() + "]", ex);
+		}
 	}
 
 }
